package com.joker.demo.core.executor.smart;

import com.joker.demo.core.config.JobExecutorProperties;
import com.joker.demo.core.domain.dto.ThreadPoolMonitorDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 线程池监控器
 * 
 * 负责收集线程池的监控信息，包括：
 * 1. 线程池基本状态信息
 * 2. 内存使用情况
 * 3. 线程堆栈信息
 * 4. 任务执行统计
 * 
 * @author : feixiang.li
 * @since : 2025-01-27 10:00
 */
public class ThreadPoolMonitor {

    private static final Logger log = LoggerFactory.getLogger(ThreadPoolMonitor.class);

    /**
     * 任务执行器配置
     */
    private final JobExecutorProperties properties;

    /**
     * 任务执行管理器
     */
    private final TaskExecutionManager taskExecutionManager;

    /**
     * 任务执行统计
     */
    private final TaskExecutionStatistics taskStatistics;

    /**
     * 构造函数
     *
     * @param properties 任务执行器配置
     * @param taskExecutionManager 任务执行管理器
     */
    public ThreadPoolMonitor(JobExecutorProperties properties, TaskExecutionManager taskExecutionManager) {
        this.properties = properties;
        this.taskExecutionManager = taskExecutionManager;
        this.taskStatistics = new TaskExecutionStatistics();
    }

    /**
     * 收集线程池监控数据
     *
     * @param registerKey 执行器标识
     * @param appName 应用名称
     * @return 监控数据
     */
    public ThreadPoolMonitorDTO collectMonitorData(String registerKey, String appName) {
        ThreadPoolMonitorDTO monitorData = new ThreadPoolMonitorDTO();
        monitorData.setRegisterKey(registerKey);
        monitorData.setAppName(appName);
        monitorData.setTimestamp(System.currentTimeMillis());

        // 收集线程池基本信息
        collectThreadPoolInfo(monitorData);

        // 收集内存使用信息
        if (properties.getThreadPoolMonitor().isMonitorMemory()) {
            collectMemoryInfo(monitorData);
        }

        // 收集线程堆栈信息
        if (properties.getThreadPoolMonitor().isMonitorThreadStack()) {
            collectThreadStackInfo(monitorData);
        }

        // 收集任务执行统计
        collectTaskStatistics(monitorData);

        return monitorData;
    }

    /**
     * 收集线程池基本信息
     */
    private void collectThreadPoolInfo(ThreadPoolMonitorDTO monitorData) {
        ThreadPoolExecutor executor = taskExecutionManager.getTaskExecutor();
        ThreadPoolMonitorDTO.ThreadPoolInfo threadPoolInfo = new ThreadPoolMonitorDTO.ThreadPoolInfo();
        
        threadPoolInfo.setCorePoolSize(executor.getCorePoolSize());
        threadPoolInfo.setMaximumPoolSize(executor.getMaximumPoolSize());
        threadPoolInfo.setPoolSize(executor.getPoolSize());
        threadPoolInfo.setActiveCount(executor.getActiveCount());
        threadPoolInfo.setQueueSize(executor.getQueue().size());
        threadPoolInfo.setQueueRemainingCapacity(executor.getQueue().remainingCapacity());
        threadPoolInfo.setCompletedTaskCount(executor.getCompletedTaskCount());
        threadPoolInfo.setTaskCount(executor.getTaskCount());
        
        monitorData.setThreadPoolInfo(threadPoolInfo);
    }

    /**
     * 收集内存使用信息
     */
    private void collectMemoryInfo(ThreadPoolMonitorDTO monitorData) {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        ThreadPoolMonitorDTO.MemoryInfo memoryInfo = new ThreadPoolMonitorDTO.MemoryInfo();
        
        long maxMemory = memoryBean.getHeapMemoryUsage().getMax();
        long totalMemory = memoryBean.getHeapMemoryUsage().getCommitted();
        long usedMemory = memoryBean.getHeapMemoryUsage().getUsed();
        long freeMemory = totalMemory - usedMemory;
        
        memoryInfo.setMaxMemoryMB(maxMemory / (1024 * 1024));
        memoryInfo.setTotalMemoryMB(totalMemory / (1024 * 1024));
        memoryInfo.setUsedMemoryMB(usedMemory / (1024 * 1024));
        memoryInfo.setFreeMemoryMB(freeMemory / (1024 * 1024));
        memoryInfo.setMemoryUsagePercent((double) usedMemory / totalMemory * 100);
        
        monitorData.setMemoryInfo(memoryInfo);
    }

    /**
     * 收集线程堆栈信息
     */
    private void collectThreadStackInfo(ThreadPoolMonitorDTO monitorData) {
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        ThreadPoolExecutor executor = taskExecutionManager.getTaskExecutor();
        
        List<ThreadPoolMonitorDTO.ThreadStackInfo> threadStackInfos = new ArrayList<>();
        
        // 获取所有线程信息
        ThreadInfo[] threadInfos = threadBean.dumpAllThreads(false, false);
        
        for (ThreadInfo threadInfo : threadInfos) {
            // 只收集线程池中的线程
            if (isThreadPoolThread(threadInfo.getThreadName(), executor)) {
                ThreadPoolMonitorDTO.ThreadStackInfo stackInfo = new ThreadPoolMonitorDTO.ThreadStackInfo();
                
                stackInfo.setThreadId(threadInfo.getThreadId());
                stackInfo.setThreadName(threadInfo.getThreadName());
                stackInfo.setThreadState(threadInfo.getThreadState().name());
                stackInfo.setDaemon(threadInfo.isInNative());
                // ThreadInfo没有getPriority方法，使用默认优先级
                stackInfo.setPriority(Thread.NORM_PRIORITY);
                
                // 获取堆栈信息
                StackTraceElement[] stackTrace = threadInfo.getStackTrace();
                if (stackTrace.length > 0) {
                    StringBuilder stackTraceBuilder = new StringBuilder();
                    for (int i = 0; i < Math.min(stackTrace.length, 10); i++) {
                        stackTraceBuilder.append(stackTrace[i].toString()).append("\n");
                    }
                    stackInfo.setStackTrace(stackTraceBuilder.toString());
                    
                    // 尝试获取当前执行的任务信息
                    String currentTask = getCurrentTaskInfo(stackTrace);
                    stackInfo.setCurrentTask(currentTask);
                }
                
                threadStackInfos.add(stackInfo);
            }
        }
        
        monitorData.setThreadStackInfos(threadStackInfos);
    }

    /**
     * 判断是否为线程池线程
     */
    private boolean isThreadPoolThread(String threadName, ThreadPoolExecutor executor) {
        // 检查线程名称是否包含线程池相关的标识
        return threadName != null && (
                threadName.contains("task-executor") ||
                threadName.contains("pool") ||
                threadName.contains("executor")
        );
    }

    /**
     * 从堆栈信息中获取当前执行的任务信息
     */
    private String getCurrentTaskInfo(StackTraceElement[] stackTrace) {
        for (StackTraceElement element : stackTrace) {
            String className = element.getClassName();
            String methodName = element.getMethodName();
            
            // 检查是否是任务执行相关的方法
            if (className.contains("TaskExecutionManager") || 
                className.contains("JobExecutor") ||
                methodName.contains("execute") ||
                methodName.contains("run")) {
                return className + "." + methodName + ":" + element.getLineNumber();
            }
        }
        return "未知任务";
    }

    /**
     * 收集任务执行统计
     */
    private void collectTaskStatistics(ThreadPoolMonitorDTO monitorData) {
        ThreadPoolMonitorDTO.TaskStatistics taskStatistics = new ThreadPoolMonitorDTO.TaskStatistics();
        
        // 获取当前运行中的任务数
        taskStatistics.setRunningTaskCount(taskExecutionManager.getThreadPoolStatus().getTaskCount());
        
        // 获取延迟任务数
        taskStatistics.setDelayTaskCount(taskExecutionManager.getDelayTaskCount());
        
        // 获取任务执行统计
        TaskExecutionStatistics.Statistics stats = this.taskStatistics.getStatistics();
        taskStatistics.setCompletedTasksLastMinute(stats.getCompletedTasksLastMinute());
        taskStatistics.setFailedTasksLastMinute(stats.getFailedTasksLastMinute());
        taskStatistics.setAverageTaskExecutionTimeMs(stats.getAverageExecutionTimeMs());
        
        monitorData.setTaskStatistics(taskStatistics);
    }

    /**
     * 记录任务完成
     */
    public void recordTaskCompletion(long executionTimeMs, boolean success) {
        taskStatistics.recordTaskCompletion(executionTimeMs, success);
    }

    /**
     * 任务执行统计
     */
    private static class TaskExecutionStatistics {
        
        private final ConcurrentHashMap<Long, Long> taskStartTimes = new ConcurrentHashMap<>();
        private final AtomicLong completedTasksLastMinute = new AtomicLong(0);
        private final AtomicLong failedTasksLastMinute = new AtomicLong(0);
        private final AtomicLong totalExecutionTime = new AtomicLong(0);
        private final AtomicLong totalCompletedTasks = new AtomicLong(0);
        
        private volatile long lastResetTime = System.currentTimeMillis();
        
        public void recordTaskCompletion(long executionTimeMs, boolean success) {
            long currentTime = System.currentTimeMillis();
            
            // 每分钟重置计数器
            if (currentTime - lastResetTime > 60000) {
                completedTasksLastMinute.set(0);
                failedTasksLastMinute.set(0);
                lastResetTime = currentTime;
            }
            
            if (success) {
                completedTasksLastMinute.incrementAndGet();
            } else {
                failedTasksLastMinute.incrementAndGet();
            }
            
            totalExecutionTime.addAndGet(executionTimeMs);
            totalCompletedTasks.incrementAndGet();
        }
        
        public Statistics getStatistics() {
            Statistics stats = new Statistics();
            stats.setCompletedTasksLastMinute(completedTasksLastMinute.get());
            stats.setFailedTasksLastMinute(failedTasksLastMinute.get());
            
            long totalTasks = totalCompletedTasks.get();
            if (totalTasks > 0) {
                stats.setAverageExecutionTimeMs((double) totalExecutionTime.get() / totalTasks);
            } else {
                stats.setAverageExecutionTimeMs(0.0);
            }
            
            return stats;
        }
        
        public static class Statistics {
            private long completedTasksLastMinute;
            private long failedTasksLastMinute;
            private double averageExecutionTimeMs;
            
            public long getCompletedTasksLastMinute() {
                return completedTasksLastMinute;
            }
            
            public void setCompletedTasksLastMinute(long completedTasksLastMinute) {
                this.completedTasksLastMinute = completedTasksLastMinute;
            }
            
            public long getFailedTasksLastMinute() {
                return failedTasksLastMinute;
            }
            
            public void setFailedTasksLastMinute(long failedTasksLastMinute) {
                this.failedTasksLastMinute = failedTasksLastMinute;
            }
            
            public double getAverageExecutionTimeMs() {
                return averageExecutionTimeMs;
            }
            
            public void setAverageExecutionTimeMs(double averageExecutionTimeMs) {
                this.averageExecutionTimeMs = averageExecutionTimeMs;
            }
        }
    }
}
